package com.ceair.config.basic;

import io.swagger.v3.core.util.PrimitiveType;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
import org.springframework.beans.BeanUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author wangbaohai
 * @ClassName BasicEnumCustomizer
 * @description: 基础自定义接口
 * @date 2025年02月21日
 * @version: 1.0.0
 */
public interface BasicEnumCustomizer {

    /**
     * 通过反射获取枚举类中所有枚举常量的"getValue"方法的返回值
     * 此方法旨在为枚举类型的每个常量调用其getValue方法（如果存在），并收集这些值到一个列表中
     * 它主要用于在不修改枚举类的情况下，获取枚举类中所有枚举常量的特定值
     *
     * @param enumClazz 枚举类的Class对象，用于反射获取枚举常量和方法
     * @return 包含所有枚举常量getValue方法返回值的列表，类型为Object的列表，需要时可以进行类型转换
     * @throws IllegalArgumentException 如果提供的不是枚举类，虽然代码中没有直接处理此异常，但它是潜在的运行时异常
     */
    default List<Object> getValues(Class<?> enumClazz) {
        // 使用反射获取枚举类的所有枚举常量
        return Arrays.stream(enumClazz.getEnumConstants()).filter(Objects::nonNull).map(item -> {
            // 收集values
            Method getValue = ReflectionUtils.findMethod(item.getClass(), "getValue");
            if (getValue != null) {
                // 确保getValue方法是可访问的，即使它是私有的
                ReflectionUtils.makeAccessible(getValue);
                // 调用getValue方法并返回结果
                return ReflectionUtils.invokeMethod(getValue, item);
            }
            return null;
        }).filter(Objects::nonNull).toList();
    }

    /**
     * 获取枚举类的描述信息
     * 此方法通过反射获取枚举类中每个枚举值的特定字段值，并将其拼接成一个字符串返回
     * 主要用于生成枚举值的详细描述，以便在需要时提供更丰富的枚举信息
     *
     * @param enumClazz 枚举类的Class对象，用于反射获取枚举类的信息
     * @return 返回一个字符串，包含每个枚举值的字段信息，按字段名称降序排列并格式化
     */
    default String getDescription(Class<?> enumClazz) {
        // 获取枚举类中所有非静态字段，并按字段名降序排序
        List<Field> fieldList =
                Arrays.stream(enumClazz.getDeclaredFields()).filter(f -> !Modifier.isStatic(f.getModifiers()))
                // 排序
                .sorted(Comparator.comparing(Field::getName).reversed()).toList();
        // 使所有字段可访问，以便后续获取其值
        fieldList.forEach(ReflectionUtils::makeAccessible);
        // 遍历每个枚举值，获取其字段信息并拼接成字符串
        return Arrays.stream(enumClazz.getEnumConstants()).filter(Objects::nonNull)
                .map(item -> fieldList.stream().map(field -> ReflectionUtils.getField(field, item)).map(String::valueOf).collect(Collectors.joining(" : ")))
                .collect(Collectors.joining("； "));
    }

    /**
     * 根据给定的类型获取对应的Schema
     * 此方法用于动态生成一个Schema对象，该对象反映了指定类型的结构和格式
     * 它首先尝试将给定类型映射到一个原始类型，如果失败，则创建一个通用的对象Schema
     * 然后，它从原始schema中复制属性，并设置新schema的类型和格式
     *
     * @param type 类型信息，用于生成具体的Schema
     * @param sourceSchema 原始的Schema，从中复制属性
     * @return 生成的Schema对象，反映了指定类型的结构和格式
     */
    @SuppressWarnings({"unchecked"})
    default Schema<Object> getSchemaByType(Type type, Schema<?> sourceSchema) {
        Schema<Object> schema;
        PrimitiveType item = PrimitiveType.fromType(type);

        if (item == null) {
            // 当无法从给定类型推导出原始类型时，创建一个通用的对象Schema
            schema = new ObjectSchema();
        } else {
            // 当可以从给定类型推导出原始类型时，创建对应的原始类型Schema
            schema = item.createProperty();
        }

        // 获取schema的type和format
        String schemaType = schema.getType();
        String format = schema.getFormat();
        // 复制原schema的其它属性
        BeanUtils.copyProperties(sourceSchema, schema);

        // 使用根据枚举值类型获取到的schema
        return schema.type(schemaType).format(format);
    }

}
